package com.ccteam.fluidmusic.fluidmusic.core

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author Xiaoc
 * @since 2021/4/15
 *
 * 关于APP相关的设置核心代码
 * 该类由Hilt管理，为单例类
 */
@Singleton
class SettingCore @Inject constructor(
    @ApplicationContext private val context: Context
) {

    companion object{
        const val KEY_DISPLAY_FLUID_MODE = "display_fluid_mode"
        const val KEY_DISPLAY_LYRICS_TEXT_SIZE = "display_lyrics_text_size"
        const val KEY_PLAY_TIMER_SWITCH = "play_timer_switch"
        const val KEY_PLAY_TIMER_SEEKBAR = "play_timer_seekBar"
        const val KEY_ACCOUNT = "account_container"
        const val KEY_ACCOUNT_EDIT_PHONE = "account_edit_phone"
        const val KEY_ACCOUNT_EDIT_PASSWORD = "account_edit_password"
        const val KEY_ACCOUNT_LOGOUT = "account_logout"
        const val KEY_OTHER_ABOUT = "other_about"
        const val KEY_UPDATE_TIME = "other_update_time"
    }

    // 协程组件
    private val serviceJob = SupervisorJob()
    private val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)

    private val _enableFluidMode = MutableStateFlow(true)
    val enableFluidMode get() = _enableFluidMode.asStateFlow()

    private val _lyricTextSize = MutableStateFlow(40)
    val lyricTextSize get() = _lyricTextSize.asStateFlow()

    private val _musicTimer = MutableStateFlow(MusicTimerData())
    val musicTimer get() = _musicTimer.asStateFlow()

    private val _settingUpdateTime = MutableStateFlow(0L)
    val settingUpdateTime get() = _settingUpdateTime.asStateFlow()

    init {
        observeSetting()
    }

    /**
     * 观察设置项的变化
     */
    private fun observeSetting(){
        serviceScope.launch {
            context.settingDataStore.data.collectLatest {
                _enableFluidMode.value = it[booleanPreferencesKey(KEY_DISPLAY_FLUID_MODE)] ?: true
                _lyricTextSize.value = it[intPreferencesKey(KEY_DISPLAY_LYRICS_TEXT_SIZE)] ?: 40
                _musicTimer.value = MusicTimerData(
                    it[booleanPreferencesKey(KEY_PLAY_TIMER_SWITCH)] ?: false,
                    it[intPreferencesKey(KEY_PLAY_TIMER_SEEKBAR)] ?: 15
                )
                _settingUpdateTime.value = it[longPreferencesKey(KEY_UPDATE_TIME)] ?: 0
            }
        }
    }

    fun updateSetting(settingJsonData: SettingJsonData){
        serviceScope.launch {
            context.settingDataStore.edit {
                it[booleanPreferencesKey(KEY_DISPLAY_FLUID_MODE)] = settingJsonData.enableFluidMode
                it[intPreferencesKey(KEY_DISPLAY_LYRICS_TEXT_SIZE)] = settingJsonData.lyricTextSize
                it[booleanPreferencesKey(KEY_PLAY_TIMER_SWITCH)] = settingJsonData.enableTimer
                it[intPreferencesKey(KEY_PLAY_TIMER_SEEKBAR)] = settingJsonData.timerCount
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun clearMusicTimer(){
        serviceScope.launch {
            context.settingDataStore.edit {
                it[booleanPreferencesKey(KEY_PLAY_TIMER_SWITCH)] = false
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun putString(key: String, value: String?) {
        serviceScope.launch(Dispatchers.IO) {
            context.settingDataStore.edit {
                it[stringPreferencesKey(key)] = value ?: ""
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun getString(key: String, defValue: String?): String? {
        return runBlocking {
            context.settingDataStore.data.map {
                it[stringPreferencesKey(key)] ?: defValue
            }.first()
        }
    }

    fun putInt(key: String, value: Int) {
        serviceScope.launch(Dispatchers.IO) {
            context.settingDataStore.edit {
                it[intPreferencesKey(key)] = value
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun getInt(key: String, defValue: Int): Int {
        return runBlocking {
            context.settingDataStore.data.map {
                it[intPreferencesKey(key)] ?: defValue
            }.first()
        }
    }

    fun putBoolean(key: String, value: Boolean) {
        serviceScope.launch(Dispatchers.IO) {
            context.settingDataStore.edit {
                it[booleanPreferencesKey(key)] = value
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun getBoolean(key: String, defValue: Boolean): Boolean {
        return runBlocking {
            context.settingDataStore.data.map {
                it[booleanPreferencesKey(key)] ?: defValue
            }.first()
        }
    }

    fun putFloat(key: String, value: Float) {
        serviceScope.launch(Dispatchers.IO) {
            context.settingDataStore.edit {
                it[floatPreferencesKey(key)] = value
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun getFloat(key: String, defValue: Float): Float {
        return runBlocking {
            context.settingDataStore.data.map {
                it[floatPreferencesKey(key)] ?: defValue
            }.first()
        }
    }

    fun putLong(key: String, value: Long) {
        serviceScope.launch(Dispatchers.IO) {
            context.settingDataStore.edit {
                it[longPreferencesKey(key)] = value
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun getLong(key: String, defValue: Long): Long {
        return runBlocking {
            context.settingDataStore.data.map {
                it[longPreferencesKey(key)] ?: defValue
            }.first()
        }
    }

    fun putStringSet(key: String, values: MutableSet<String>?) {
        serviceScope.launch(Dispatchers.IO) {
            context.settingDataStore.edit {
                it[stringSetPreferencesKey(key)] = values ?: setOf()
                it[longPreferencesKey(KEY_UPDATE_TIME)] = System.currentTimeMillis()
            }
        }
    }

    fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String> {
        return runBlocking {
            context.settingDataStore.data.map {
                it[stringSetPreferencesKey(key)] ?: defValues ?: setOf()
            }.first().toMutableSet()
        }
    }

    /**
     * 定时关闭的数据类
     * @param enableTimer 是否开启定时关闭
     * @param timerCount 定时关闭时长(min)
     */
    data class MusicTimerData(
        var enableTimer: Boolean = false,
        var timerCount: Int = 15
    )
}

data class SettingJsonData(
    val enableFluidMode: Boolean,
    val lyricTextSize: Int,
    val enableTimer: Boolean = false,
    val timerCount: Int
)

private val Context.settingDataStore:
        DataStore<Preferences> by preferencesDataStore(name = "fluidmusic-settings")